Skip to content

feat(api): add clerk api --fapi for the public Frontend API#345

Merged
rafa-thayto merged 4 commits into
mainfrom
feat/api-fapi-passthrough
Jun 22, 2026
Merged

feat(api): add clerk api --fapi for the public Frontend API#345
rafa-thayto merged 4 commits into
mainfrom
feat/api-fapi-passthrough

Conversation

@rafa-thayto

Copy link
Copy Markdown
Contributor

Summary

clerk api spoke only BAPI (default) and PLAPI (--platform). After a config change, the natural way to verify it took effect is the instance's public FAPI /v1/environment payload (what clerk-js actually consumes) — but that meant dropping to curl plus decoding the FAPI domain out of the publishable key by hand.

This adds --fapi:

clerk api --fapi /environment --app <id> --instance dev
  • Resolves the FAPI host from the instance's publishable key (looked up via --app/--instance or the linked project through the Platform API), reusing the existing lib/fapi.ts client and decodePublishableKey.
  • The request itself is unauthenticated — these endpoints are public.
  • Paths are /v1-normalized like the other modes, so both /environment and /v1/environment work.
  • --fapi and --platform are mutually exclusive.

Implementation reuses the request-target resolution: api() now builds a { baseUrl, runRequest } pair, which also de-duplicates the BAPI/PLAPI branches. The local error handler was broadened from BapiError to ApiError so FAPI error bodies still print to stdout for piping.

Test plan

  • New tests in src/commands/api/index.test.ts: host resolution + no auth header; --fapi/--platform conflict; FAPI error body printed to stdout with exit 1
  • Full api + completion + api-queries integration suites pass

Closes #332

@changeset-bot

changeset-bot Bot commented Jun 16, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: efa6d41

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
clerk Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai

coderabbitai Bot commented Jun 16, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

A new --fapi flag is added to the clerk api command, routing requests to the instance's public Frontend API. A shared ApiResponse interface is introduced in lib/fetch.ts and adopted by both bapiRequest and a new fapiRequest function in lib/fapi.ts. A new commands/api/fapi.ts module resolves the FAPI host from the instance's publishable key via Platform API. In commands/api/index.ts, validateFapiOptions() enforces mutual exclusion with --platform and warns on ignored --secret-key; resolveApiTarget() dispatches to the appropriate request executor. CLERK_JS_API_VERSION is bumped from "5" to "6". Tests and README documentation are updated accordingly.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(api): add clerk api --fapi for the public Frontend API' clearly and specifically summarizes the main change: adding a --fapi flag to the clerk api command for Frontend API support.
Description check ✅ Passed The description comprehensively explains the feature being added, its purpose, usage, implementation details, and testing approach, all directly related to the changeset.
Linked Issues check ✅ Passed The PR fully implements the requirements from issue #332: adds 'clerk api --fapi' to resolve FAPI host from instance publishable key, supports --app/--instance parameters, makes unauthenticated requests to public endpoints, and enables config verification without external tools.
Out of Scope Changes check ✅ Passed All changes are scoped to implementing the --fapi feature: new FAPI request functionality, instance resolution logic, comprehensive tests, documentation updates, and refactoring to support multiple API targets without out-of-scope modifications.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@wyattjoh wyattjoh left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clean, well-scoped addition that mirrors the existing BAPI/PLAPI passthrough patterns. A few follow-ups around dry-run semantics, a duplicated version constant, and silently-ignored flags.

Comment thread packages/cli-core/src/commands/api/index.ts Outdated
Comment thread packages/cli-core/src/commands/api/fapi.ts Outdated
Comment thread packages/cli-core/src/commands/api/fapi.ts
Comment thread packages/cli-core/src/commands/api/index.ts
Comment thread packages/cli-core/src/commands/api/index.test.ts
clerk api spoke only BAPI and PLAPI, so verifying a config change against the
instance's public FAPI /v1/environment (what clerk-js consumes) meant dropping
to curl and decoding the FAPI domain out of the publishable key by hand.

Add --fapi: resolve the FAPI host from the instance's publishable key (via
--app/--instance or the linked project) and do an unauthenticated passthrough,
reusing the existing lib/fapi.ts client. --fapi and --platform are mutually
exclusive.

Closes #332
- Move dry-run check before resolveFapiHost so --fapi --dry-run avoids
  the Platform API round-trip; shows <fapi-host> placeholder instead
- Import CLERK_JS_API_VERSION from lib/fapi.ts instead of redeclaring it
- Warn when --secret-key is provided with --fapi (key is ignored)
- Add tests: --fapi no-app NOT_LINKED error, /environment and
  /v1/environment path normalization, --secret-key warning, --dry-run
  no network call
@rafa-thayto rafa-thayto force-pushed the feat/api-fapi-passthrough branch from 8f9d521 to 64f6f75 Compare June 18, 2026 12:19
@rafa-thayto rafa-thayto requested a review from wyattjoh June 18, 2026 12:19
Comment thread packages/cli-core/src/lib/fapi.ts Outdated
Comment thread packages/cli-core/src/commands/api/index.ts Outdated

@dmoerner dmoerner left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should just be clearer that this only hits public endpoints.

Because it is possible to use the command line to hit FAPI with curl, and use auth, you just need to use a cookie jar. This is how I do it in my local skill for testing:

FAPI=""
jar=$(mktemp)

# 1. Create a dev browser; capture its token.
tok=$(curl -s -c "$jar" -X POST "$FAPI/v1/dev_browser" -H "Origin: $FAPI" | jq -r '.token')

# 2. Inspect what the instance has enabled (strategies, factors).
curl -s -b "$jar" -c "$jar" "$FAPI/v1/environment?__clerk_db_jwt=$tok" -H "Origin: $FAPI" \
  | jq '.auth_config | {first_factors, identification_strategies, password}'

# 3. The client state (sessions, sign_in, sign_up).
curl -s -b "$jar" -c "$jar" "$FAPI/v1/client?__clerk_db_jwt=$tok" -H "Origin: $FAPI" \
  | jq '.response | {sessions: (.sessions|length)}'

- Refactor fallback branch of resolveInstance to use
  resolveFetchedApplicationInstance instead of hand-rolling
  app.instances.find (addresses wyattjoh comment 3)
- Bump CLERK_JS_API_VERSION from "5" to "6" to match current clerk-js
  major (addresses dmoerner comment 6)
- Clarify --fapi help text: "unauthenticated endpoints only" instead of
  "no auth" to avoid implying it skips auth on authenticated endpoints
  (addresses dmoerner comment 7)
Comment thread packages/cli-core/src/commands/api/fapi.ts Outdated
Co-locate the FAPI passthrough request with the other FAPI helpers
(bootstrapDevBrowser, fetchUserSettings) in lib/fapi.ts, where it
already reached for decodePublishableKey and CLERK_JS_API_VERSION.

Promote the passthrough response shape to a shared `ApiResponse` type
in lib/fetch.ts so the moved function does not have to import upward
from commands/. commands/api/fapi.ts keeps the command-layer instance
and host resolution.

Addresses review feedback on #345.

Claude-Session: https://claude.ai/code/session_01QnfBw9qY7u19BvUWyfQGC6

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/cli-core/src/lib/fapi.ts`:
- Around line 137-140: The normalizeBapiPath function in the URL construction at
line 137 doesn't correctly handle paths that already contain query strings. When
options.path contains a query string like /v1?foo=bar, normalizeBapiPath can
double-normalize it incorrectly. Separate the path and query string components
of options.path before normalizing, apply normalizeBapiPath only to the path
portion, and then properly reconstruct the URL using the URL constructor so that
both the normalized path and query parameters are handled correctly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1a82c2ba-4088-4f74-b89d-9039b59ff605

📥 Commits

Reviewing files that changed from the base of the PR and between e1b5db3 and efa6d41.

📒 Files selected for processing (5)
  • packages/cli-core/src/commands/api/bapi.ts
  • packages/cli-core/src/commands/api/fapi.ts
  • packages/cli-core/src/commands/api/index.ts
  • packages/cli-core/src/lib/fapi.ts
  • packages/cli-core/src/lib/fetch.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/cli-core/src/commands/api/index.ts

Comment on lines +137 to +140
const url = new URL(`https://${options.fapiHost}${normalizeBapiPath(options.path)}`);
if (!url.searchParams.has("_clerk_js_version")) {
url.searchParams.set("_clerk_js_version", CLERK_JS_API_VERSION);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Handle /v1 paths with query strings correctly.

At Line 137, using normalizeBapiPath() can mis-normalize /v1?foo=bar into /v1/v1?foo=bar because the helper only treats / or end-of-string as valid after v1.

Suggested fix (in packages/cli-core/src/lib/bapi-command.ts)
-  if (!/^\/v1(?:\/|$)/.test(normalized)) normalized = `/v1${normalized}`;
+  if (!/^\/v1(?:\/|$|\?)/.test(normalized)) normalized = `/v1${normalized}`;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/cli-core/src/lib/fapi.ts` around lines 137 - 140, The
normalizeBapiPath function in the URL construction at line 137 doesn't correctly
handle paths that already contain query strings. When options.path contains a
query string like /v1?foo=bar, normalizeBapiPath can double-normalize it
incorrectly. Separate the path and query string components of options.path
before normalizing, apply normalizeBapiPath only to the path portion, and then
properly reconstruct the URL using the URL constructor so that both the
normalized path and query parameters are handled correctly.

@rafa-thayto rafa-thayto merged commit 694188c into main Jun 22, 2026
10 checks passed
@rafa-thayto rafa-thayto deleted the feat/api-fapi-passthrough branch June 22, 2026 19:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature: fetch an instance's public FAPI /v1/environment for config verification

3 participants